//
//  WXUtils.m
//  UtilsDemo
//
//  Created by wulanzhou on 16/10/2.
//  Copyright © 2016年 wulanzhou. All rights reserved.
//

#import "WXUtils.h"
#import <CommonCrypto/CommonCryptor.h>
#import <CommonCrypto/CommonDigest.h>
#import "WXApi.h"

@interface WXUtils ()<WXApiDelegate>
@property (nonatomic,copy) WXPayFininshedBlock payFinishedBlock;
@property (nonatomic,copy) WXShareFininshedBlock shareFinishedBlock;
@end

@implementation WXUtils

/**
 *  单例
 *
 *  @return
 */
+ (WXUtils *)shareInstance
{
    static dispatch_once_t  onceToken;
    static WXUtils * sSharedInstance;
    
    dispatch_once(&onceToken, ^{
        sSharedInstance = [[WXUtils alloc] init];
    });
    return sSharedInstance;
}

- (id)init{
    if (self=[super init]) {
        
        self.appId=@"wxefffce4487a046fc";
        self.appAppSecret=@"ece56b32cc1082d610a5eebb87a2a620";
        self.partnerId=@"1250121901";
        
        /**
        self.appId=@"wx3f0e2b2c151c6940";
        self.appAppSecret=@"hGS3GSDWsd3SDFsdfddfgDFGssd566f6";
        self.partnerId=@"1323510401";
         **/
    }
    return self;
}


/**
 *  注册微信支付
 */
- (void)regisetWXPay{
    [WXApi registerApp:self.appId];
}

/**
 *  判断是否有安装微信
 *
 *  @return
 */
- (BOOL)isisWXAppInstalled{
    //判断是否有安装客户端
    if (![WXApi isWXAppInstalled] && ![WXApi isWXAppSupportApi]){
        
        //[AlertHelper showAlertWithMessage:@"未安装微信客户端,无法支付!"];
        return NO;
    }
    return YES;
}


//打开网址,应用调用handleOpenURL时调用
- (BOOL)handleOpenURL:(NSURL *)url{
    return [WXApi handleOpenURL:url delegate:self];
}




#pragma mark - 微信支付回调处理
- (void)onResp:(BaseResp *)resp
{
    
    //NSLog(@"resp class =%@",[resp class]);
    
    BOOL paySuccess=NO;
    NSString *errCode=nil,*errMsg=nil;
    
    if (resp.errCode==WXSuccess) {
        paySuccess=YES;
    }else{
        
        if (resp.errCode == WXErrCodeUserCancel) {
            errMsg = [resp isKindOfClass:[PayResp class]]?@"取消支付":([resp isKindOfClass:[SendMessageToWXResp class]]?@"取消分享":@"用户取消");
        }else{
            errMsg =resp.errStr;
        }
        
        errCode=[NSString stringWithFormat:@"%d",resp.errCode];
        
    }
    
    if([resp isKindOfClass:[PayResp class]]){ //微信支付回调
        if (self.payFinishedBlock) {
            self.payFinishedBlock(paySuccess,errCode,errMsg);
        }
        self.payFinishedBlock = nil;
    }
    
    if ([resp isKindOfClass:[SendMessageToWXResp class]]) { //微信分享回调
        if (self.shareFinishedBlock) {
            self.shareFinishedBlock(paySuccess,errCode,errMsg);
        }
        self.shareFinishedBlock = nil;
    }

}


#pragma mark -微信支付三步曲

/**
 *  取得微信支付访问权限gettoken
 *
 *  @param finished 取得微信支付token回调
 */
- (void)requestWXPayTokenWithCompleted:(void(^)(NSString *token,NSError *error))finished{
    NSString *getAccessTokenUrl = [NSString stringWithFormat:@"https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%@&secret=%@", self.appId, self.appAppSecret];
    
    
    // 1.创建一个网络路径
    NSURL *url = [NSURL URLWithString:getAccessTokenUrl];
    // 2.创建一个网络请求，分别设置请求方法、请求参数
    NSMutableURLRequest *request =[NSMutableURLRequest requestWithURL:url];
    request.HTTPMethod = @"POST";
    //NSString *args = [NSString stringWithFormat:@"yourname=%@&yourpass=%@&btn=login",yourname,yourpass];
    //request.HTTPBody = [args dataUsingEncoding:NSUTF8StringEncoding];
    // 3.获得会话对象
    NSURLSession *session = [NSURLSession sharedSession];
    // 4.根据会话对象，创建一个Task任务
    NSURLSessionDataTask *sessionDataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        NSLog(@"从服务器获取到数据");
        
        
        if (error) {
            NSLog(@"请求失败 =%@",error);
            if (finished) {
                finished(nil,error);
            }
            return;
        }
        
        NSError *err = nil;
        /*
         对从服务器获取到的数据data进行相应的处理.
         */
        NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:(NSJSONReadingMutableLeaves) error:&err];
        
        if (err) {
            NSLog(@"json解析失败 =%@",error);
            if (finished) {
                finished(nil,error);
            }
            return;
        }
        
        
        NSString *accessToken = dict[@"access_token"];
        if (accessToken) {
            if (finished) {
                finished(accessToken,nil);
            }
        } else {
            NSString *strMsg = [NSString stringWithFormat:@"errcode: %@, errmsg:%@", dict[@"errcode"], dict[@"errmsg"]];
            NSDictionary* userInfo = [NSDictionary dictionaryWithObject:strMsg forKey:NSLocalizedDescriptionKey];
            NSError *error_ = [[NSError alloc] initWithDomain:@"ServiceRequestManager"
                                                         code:[dict[@"errcode"] integerValue]
                                                     userInfo:userInfo];
            
            if (finished) {
                finished(nil,error_);
            }
        }

    }];
    //5.最后一步，执行任务，(resume也是继续执行)。
    [sessionDataTask resume];
    
   
}

/**
 *  取得微信支付预支付id[微信支付第二步]
 *
 *  @param token          访问权限token[微信支付第一步]
 *  @param productData    订单数据
 *  @param finished       取得预支付id回调
 */
- (void)requestWXPayPrepayIdWithToken:(NSString*)token productData:(NSData*)productData completed:(void(^)(NSString *prepayId,NSError *error))finished{
    
    NSString *getPrepayIdUrl = [NSString stringWithFormat:@"https://api.weixin.qq.com/pay/genprepay?access_token=%@", token];
    
    
    // 1.创建一个网络路径
    NSURL *url = [NSURL URLWithString:getPrepayIdUrl];
    // 2.创建一个网络请求，分别设置请求方法、请求参数
    NSMutableURLRequest *request =[NSMutableURLRequest requestWithURL:url];
    request.HTTPMethod = @"POST";
    [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
    [request setValue:@"application/json" forHTTPHeaderField:@"Accept"];
    request.HTTPBody=productData;
    // 3.获得会话对象
    NSURLSession *session = [NSURLSession sharedSession];
    // 4.根据会话对象，创建一个Task任务
    NSURLSessionDataTask *sessionDataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        
        if (error) {
            NSLog(@"请求失败 =%@",error);
            if (finished) {
                finished(nil,error);
            }
            return;
        }

        NSError *err = nil;
        /*
         对从服务器获取到的数据data进行相应的处理.
         */
        NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:(NSJSONReadingMutableLeaves) error:&err];
        
        if (err) {
            NSLog(@"json解析失败 =%@",error);
            if (finished) {
                finished(nil,error);
            }
            return;
        }
        
        NSString *prePayId = dict[@"prepayid"];
        if (prePayId) {
            if (finished) {
                finished(prePayId,nil);
            }
        } else {
            NSString *strMsg = [NSString stringWithFormat:@"errcode: %@, errmsg:%@", dict[@"errcode"], dict[@"errmsg"]];
            NSDictionary* userInfo = [NSDictionary dictionaryWithObject:strMsg forKey:NSLocalizedDescriptionKey];
            NSError *error_ = [[NSError alloc] initWithDomain:@"ServiceRequestManager"
                                                         code:[dict[@"errcode"] integerValue]
                                                     userInfo:userInfo];
            
            if (finished) {
                finished(nil,error_);
            }
        }
        
    
    }];
    [sessionDataTask resume];
    
}

/**
 *  微信支付
 *
 *  @param wxAppId             appId
 *  @param wxPartnerId         商户id
 *  @param prepay_id           预支付id
 *  @param nonceStr            随机字符串
 *  @param timestamp           时间戳
 *  @param sign                签名
 *  @param aPayFinishedBlock   支付结果回调
 */
- (void)payWithAppId:(NSString *)wxAppId
           partnerId:(NSString *)wxPartnerId
            perpayId:(NSString*)prepay_id
            nonceStr:(NSString *)nonceStr
           timeStamp:(UInt32)timestamp
                sign:(NSString *)sign
        payCompleted:(WXPayFininshedBlock)aPayFinishedBlock{

    self.payFinishedBlock = aPayFinishedBlock;
    //调起微信支付
    PayReq* req             = [[PayReq alloc] init];
    req.openID              = wxAppId;
    req.partnerId           = wxPartnerId;
    req.prepayId            = prepay_id;
    req.nonceStr            = nonceStr;
    req.timeStamp           = timestamp;
    req.package             = @"Sign=WXPay";
    req.sign                = sign;
    
    [WXApi sendReq:req];
}

/**
 *  微信支付(必须保证 appId，partnerId属性配置值不能有误)
 *
 *  @param prepay_id         预支付id
 *  @param nonceStr          随机字符串
 *  @param timestamp         时间戳
 *  @param sign              签名
 *  @param aPayFinishedBlock 支付结果回调
 */
- (void)payWithPerpayId:(NSString*)prepay_id
               nonceStr:(NSString *)nonceStr
              timeStamp:(UInt32)timestamp
                   sign:(NSString *)sign
           payCompleted:(WXPayFininshedBlock)aPayFinishedBlock{

    [self payWithAppId:self.appId partnerId:self.partnerId perpayId:prepay_id nonceStr:nonceStr timeStamp:timestamp sign:sign payCompleted:aPayFinishedBlock];
}

/**
 *  微信支付 (必须保证 appId，appAppSecret，partnerId属性配置值不能有误)
 *
 *  @param prepay_id         预支付id
 *  @param aPayFinishedBlock 支付结果回调
 */
- (void)payWithPerpayId:(NSString*)prepay_id
           payCompleted:(WXPayFininshedBlock)aPayFinishedBlock{

    NSDictionary *wxPayDic = [self wxPaySignParamWithPrepayId:prepay_id];

    [self payWithAppId:[wxPayDic objectForKey:@"appid"] partnerId:[wxPayDic objectForKey:@"partnerid"] perpayId:prepay_id nonceStr:[wxPayDic objectForKey:@"noncestr"] timeStamp:[[wxPayDic objectForKey:@"timestamp"] intValue] sign:[self wxPayMd5SignString:wxPayDic] payCompleted:aPayFinishedBlock];
    
    /**
    self.payFinishedBlock = aPayFinishedBlock;
    //调起微信支付
    PayReq* req             = [[PayReq alloc] init];
    req.openID              = self.appId;
    req.partnerId           = self.partnerId;
    req.prepayId            = prepay_id;
    req.nonceStr            = [wxPayDic objectForKey:@"noncestr"];
    req.timeStamp           = [[wxPayDic objectForKey:@"timestamp"] intValue];
    req.package             = @"Sign=WXPay";
    req.sign                =[self wxPayMd5SignString:wxPayDic];

    [WXApi sendReq:req];
     **/
}

#pragma mark -签名处理
/**
 *  取得微信支付签名参数
 *
 *  @param prepayId 预支付Id
 *  @return         签名参数
 */
- (NSDictionary*)wxPaySignParamWithPrepayId:(NSString*)prepayId{
    
    UInt32 timeStamp=[[NSDate date] timeIntervalSince1970];
    
    NSMutableDictionary *signParams = [NSMutableDictionary dictionary];
    [signParams setObject:self.appId        forKey:@"appid"];
    [signParams setObject:self.partnerId forKey:@"partnerid"];
    [signParams setObject:[self wxPayNonceString]    forKey:@"noncestr"];
    [signParams setObject:@"Sign=WXPay"      forKey:@"package"];
    [signParams setObject: [NSString stringWithFormat:@"%d",(unsigned int)timeStamp]   forKey:@"timestamp"];
    [signParams setObject: prepayId     forKey:@"prepayid"];
    
    return signParams;
}

/**
 *  取得微信支付md5签名字符串
 *
 *  @param dict 签名参数
 *
 *  @return 签名字符串
 */
- (NSString*)wxPayMd5SignString:(NSDictionary*)dict{
    NSMutableString *contentString  =[NSMutableString string];
    NSArray *keys = [dict allKeys];
    //按字母顺序排序
    NSArray *sortedArray = [keys sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
        return [obj1 compare:obj2 options:NSNumericSearch];
    }];
    //拼接字符串
    for (NSString *categoryId in sortedArray) {
        if (   ![[dict objectForKey:categoryId] isEqualToString:@""]
            && ![[dict objectForKey:categoryId] isEqualToString:@"sign"]
            && ![[dict objectForKey:categoryId] isEqualToString:@"key"]
            )
        {
            [contentString appendFormat:@"%@=%@&", categoryId, [dict objectForKey:categoryId]];
        }
    }
    //添加key字段
    [contentString appendFormat:@"key=%@", self.appAppSecret];
    //得到MD5 sign签名
    NSString *md5Sign =[self md5:contentString];
    
    return [md5Sign uppercaseString];
}
#pragma mark -私有方法
/**
 *  生成随机串，防重发
 *
 *  @return 随机串
 */
- (NSString*)wxPayNonceString{
    NSString *randomString = [NSString stringWithFormat:@"%d",arc4random()%100000];
    return [self md5:randomString];
}

/**
 *  字符串md5加密
 *
 *  @param str 需要加密的字符串
 *
 *  @return md5加密字符串
 */
- (NSString*)md5:(NSString*)str{
    const char *cStr = [str UTF8String];
    unsigned char result[16];
    CC_MD5( cStr, (CC_LONG)strlen(cStr), result );
    return [[NSString stringWithFormat:
             @"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
             result[0], result[1], result[2], result[3],
             result[4], result[5], result[6], result[7],
             result[8], result[9], result[10], result[11],
             result[12], result[13], result[14], result[15]
             ] lowercaseString];
}

#pragma mark - 分享朋友或朋友圈

/**
 分享给朋友
 
 @param shareTitle          分享标题
 @param shareMsg            分享内容
 @param shareImgData        分享缩图
 @param shareUrl            分享的url
 @param aShareFinishedBlock 分享结果回调
 */
- (void)shareToFriendWithTitle:(NSString *)shareTitle
                       message:(NSString *)shareMsg
                     imageData:(NSData *)shareImgData
                       linkUrl:(NSString *)shareUrl
                shareCompleted:(WXShareFininshedBlock)aShareFinishedBlock
{
    
    NSLog(@"微信分享给好友");
    
    self.shareFinishedBlock=aShareFinishedBlock;
    
    SendMessageToWXReq *req = [[SendMessageToWXReq alloc] init];
    req.scene = WXSceneSession;
    
    WXMediaMessage *message = [[WXMediaMessage alloc]init];
    message.title = shareTitle;
    message.description = shareMsg;
    
    if (shareImgData) {
        message.thumbData = shareImgData;
    }

    WXWebpageObject *ext = [WXWebpageObject object];
    ext.webpageUrl = shareUrl;
    message.mediaObject = ext;
    
    req.message = message;
    [WXApi sendReq:req];
}

/**
 分享到朋友圈
 
 @param shareTitle          分享标题
 @param shareMsg            分享内容(内容不会显示)
 @param shareImgData        分享缩图
 @param shareUrl            分享的url
 @param aShareFinishedBlock 分享结果回调
 */
- (void)shareToFriendGroupWithTitle:(NSString *)shareTitle
                            message:(NSString *)shareMsg
                          imageData:(NSData *)shareImgData
                            linkUrl:(NSString *)shareUrl
                     shareCompleted:(WXShareFininshedBlock)aShareFinishedBlock
{
    
    NSLog(@"微信分享给朋友圈");
    
    self.shareFinishedBlock=aShareFinishedBlock;
    
    SendMessageToWXReq *req = [[SendMessageToWXReq alloc] init];
    req.scene = WXSceneTimeline;
    
    WXMediaMessage *message = [[WXMediaMessage alloc]init];
    message.title =shareTitle;
    message.description = shareMsg;
    
    if (shareImgData) {
        message.thumbData = shareImgData;
    }
    
    WXWebpageObject *ext = [WXWebpageObject object];
    ext.webpageUrl = shareUrl;
    message.mediaObject = ext;
    
    req.message = message;
    [WXApi sendReq:req];
}

@end
